// udp_rpc_server.go
//
// 功能：基于 UDP 的简易 JSON-RPC 服务端。
// 流程：
//   1. 监听指定 UDP 地址，循环读取报文。
//   2. 解析 JSON 请求，执行业务逻辑（本例为整数求和）。
//   3. 将结果序列化为 JSON，通过 UDP 回写给请求端。
//   4. 每个请求分配 goroutine 处理，保证高并发场景不会阻塞主循环。
// 关键点：
//   - UDP 本身是无连接协议，每个报文需要携带请求 ID，便于客户端匹配响应。
//   - 采用 context 控制 goroutine 生命周期（此处示例简单，未引入取消逻辑）。
//   - 日志包含 remoteAddr、requestID 等关键信息，方便排查问题。

package main

import (
	"context"
	"encoding/json"
	"fmt"
	"log"
	"net"
	"time"
)

// serverAddr 指定服务器监听地址。
const serverAddr = "127.0.0.1:9000"

// AddRequest 定义加法请求的 JSON 结构。
type AddRequest struct {
	RequestID string  `json:"request_id"`
	A         float64 `json:"a"`
	B         float64 `json:"b"`
}

// AddResponse 定义加法响应的 JSON 结构。
type AddResponse struct {
	RequestID string  `json:"request_id"`
	Sum       float64 `json:"sum"`
	Error     string  `json:"error,omitempty"` // 出错时携带错误信息
}

func main() {
	addr, err := net.ResolveUDPAddr("udp", serverAddr)
	if err != nil {
		log.Fatalf("解析地址失败: %v", err)
	}

	conn, err := net.ListenUDP("udp", addr)
	if err != nil {
		log.Fatalf("监听 UDP 失败: %v", err)
	}
	defer conn.Close()

	log.Printf("[server] UDP 服务启动，监听 %s", serverAddr)

	// 主循环：不断读取 UDP 报文。
	for {
		buf := make([]byte, 4096) // 每个报文最大 4KB，可按需调整
		n, remoteAddr, err := conn.ReadFromUDP(buf)
		if err != nil {
			log.Printf("[server] 读取报文失败: %v", err)
			continue
		}

		data := make([]byte, n)
		copy(data, buf[:n])

		// 每个请求交给单独 goroutine 处理，避免主循环阻塞。
		go handlePacket(context.Background(), conn, remoteAddr, data)
	}
}

// handlePacket 解析请求、执行业务并返回响应。
func handlePacket(ctx context.Context, conn *net.UDPConn, remoteAddr *net.UDPAddr, data []byte) {
	var req AddRequest
	if err := json.Unmarshal(data, &req); err != nil {
		log.Printf("[server] JSON 解析失败 remote=%s err=%v raw=%q", remoteAddr, err, string(data))
		sendError(conn, remoteAddr, "", fmt.Sprintf("invalid json: %v", err))
		return
	}

	start := time.Now()
	log.Printf("[server] 收到请求 id=%s remote=%s payload=a:%v b:%v", req.RequestID, remoteAddr, req.A, req.B)

	sum := req.A + req.B // 业务逻辑：求和

	resp := AddResponse{
		RequestID: req.RequestID,
		Sum:       sum,
	}

	respBytes, err := json.Marshal(resp)
	if err != nil {
		log.Printf("[server] JSON 序列化失败 id=%s err=%v", req.RequestID, err)
		sendError(conn, remoteAddr, req.RequestID, fmt.Sprintf("encode error: %v", err))
		return
	}

	if _, err := conn.WriteToUDP(respBytes, remoteAddr); err != nil {
		log.Printf("[server] 回写响应失败 id=%s err=%v", req.RequestID, err)
		return
	}

	elapsed := time.Since(start)
	log.Printf("[server] 请求完成 id=%s sum=%v 耗时=%s", req.RequestID, sum, elapsed)
}

// sendError 构造错误响应并发送。
func sendError(conn *net.UDPConn, remoteAddr *net.UDPAddr, requestID, message string) {
	resp := AddResponse{
		RequestID: requestID,
		Error:     message,
	}
	payload, err := json.Marshal(resp)
	if err != nil {
		log.Printf("[server] 序列化错误响应失败 requestID=%s err=%v", requestID, err)
		return
	}
	if _, err := conn.WriteToUDP(payload, remoteAddr); err != nil {
		log.Printf("[server] 发送错误响应失败 requestID=%s err=%v", requestID, err)
	}
}
